package main

import (
	"fmt"
	"sync"
	"sync/atomic"
)

// 测试多个协程从sync.map中读取变量，在对变量操作，会不会因为竞争导致结果和期待的不一致

type Data struct {
	mu sync.Mutex
	Pkgs uint64
}

var cache sync.Map

func main() {
	cache = sync.Map{}
	cache.Store("key_01", &Data{sync.Mutex{},0})

	// 100000个协程并发访问cache
	wg := sync.WaitGroup{}

	for i := 0; i < 100000; i++ {
		wg.Add(1)
		go func(wg *sync.WaitGroup) {
			defer wg.Done()

			v,ok := cache.Load("key_01")
			if !ok {
				fmt.Println("key_01 not found")
				return
			}
			d,ok := v.(*Data)
			if !ok {
				fmt.Println("value not Data")
				return
			}
			// 1.使用sync.mutex -> 结果正确
			//d.mu.Lock()
			//d.Pkgs++
			//d.mu.Unlock()

			// 2.不加锁结果不正确
			//d.Pkgs++

			// 3.使用原子操作结果正确
			atomic.AddUint64(&d.Pkgs, 1)
		}(&wg)
	}
	wg.Wait()

	v,ok := cache.Load("key_01")
	if !ok {
		fmt.Println("key_01 not found")
		return
	}
	d,ok := v.(*Data)
	if !ok {
		fmt.Println("value not Data")
		return
	}
	fmt.Println("pkgs : ", d.Pkgs)
	atomic.CompareAndSwapUint64(&d.Pkgs, d.Pkgs, 0)
	fmt.Println("pkgs : ", d.Pkgs)
}